/**
 * Copyright (c) 2009 Cerner Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Cerner Corporation - initial API and implementation
 */
package com.cerner.system.rest.resource.organizer;

import java.net.URI;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import com.cerner.system.rest.resource.organizer.spi.ResourceKey;
import com.cerner.system.rest.resource.organizer.spi.ThreadSafe;

/**
 * Thread-safe {@link ResourceOrganizer} implementation that allows for the
 * organization of resources in a hierarchical tree structure maintained by a
 * {@link java.util.Map} data structure.
 * 
 * @author Alex Horn
 * @param <E> class type of objects that should be cached
 */
@ThreadSafe
public class ConcurrentMapResourceOrganizer<E> implements ResourceOrganizer<E> {

  /**
   * Components that would like to read from or write to the map must acquire
   * the appropriate lock via {@link #getReadLock()} and {@link #getWriteLock()}
   * .
   */
  private final MapResourceOrganizer<E> organizer;

  /**
   * Reentrant read-write lock that protects the {@link #organizer} data
   * structure.
   */
  private final ReadWriteLock organizerLock;

  /**
   * Instantiate a thread-safe {@link ResourceOrganizer} object that stores
   * resources as entries in an in-memory {@link java.util.Map} data structure.
   * <p>
   * The base URI is used to {@link #resource(java.net.URI) resolve} resource
   * URIs.
   * 
   * @param baseURI base URI must conform to the <a
   *          href="http://tools.ietf.org/html/rfc3986#section-4.3"
   *          >&lt;absolute-URI&gt; syntax rule</a>
   * @throws IllegalArgumentException if the base URI is {@code null} or it does
   *           not conform to the <a
   *           href="http://tools.ietf.org/html/rfc3986#section-4.3"
   *           >&lt;absolute-URI&gt; syntax rule</a>
   */
  public ConcurrentMapResourceOrganizer(final java.net.URI baseURI) {
    this.organizer = new MapResourceOrganizer<E>(baseURI);
    this.organizerLock = new ReentrantReadWriteLock();
  }

  /*
   * Write lock acquisition on map data structure
   */
  public void clear() {
    final Lock writeLock = getWriteLock();
    writeLock.lock();
    try {
      this.organizer.clear();
    } finally {
      writeLock.unlock();
    }
  }

  /*
   * No lock acquisition
   */
  public URI baseURI() {
    return this.organizer.baseURI();
  }

  /*
   * No lock acquisition
   */
  public ConcurrentMapResourceController<E> resource(final java.net.URI uri) {
    final ResourceKey key = new ResourceKey(baseURI(), uri);
    final MapResourceController<E> controller = new MapResourceController<E>(
        key, this.organizer);

    return new ConcurrentMapResourceController<E>(controller, this);
  }

  /**
   * Obtain a read lock on the underlying map data structure.
   * 
   * @return read lock
   */
  public Lock getReadLock() {
    return this.organizerLock.readLock();
  }

  /**
   * Obtain a write lock on the underlying map data structure.
   * 
   * @return write lock
   */
  public Lock getWriteLock() {
    return this.organizerLock.writeLock();
  }

}
